﻿using System;
using DoubleAspect;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace UnitTests
{
    [TestClass]
    public class ReplaceStaticMethodsTest
    {
        private Moq.Mock<ICall> _callSpy;
        private Moq.Mock<ICall> _callSpyAspect;

        [TestInitialize]
        public void Initialize()
        {
            _callSpy = new Moq.Mock<ICall>();
            _callSpyAspect = new Moq.Mock<ICall>();
            ReplacedStatic.CallSpy = _callSpy.Object;
            Instrumentation.ClearBeforeActions();
        }

        public static void Hoshi()
        {

        }

        [TestMethod]
        public void WhenCallReplacedMethod0ArgsThenExecuteMethodBody()
        {
            Instrumentation.EncapsulateNonjittedMethod(typeof(ReplacedStatic).GetMethod("ZeroArgs"));

            ReplacedStatic.ZeroArgs();

            _callSpy.Verify(x => x.Execute(), Moq.Times.Once());
        }

        [TestMethod]
        public void WhenCallReplacedMethod0ArgsThenExecuteBeforeMethod()
        {
            var spy = _callSpyAspect.Object;
            Instrumentation.AddBeforeAction("ZeroArgs", x => spy.Execute());
            Instrumentation.EncapsulateNonjittedMethod(typeof(ReplacedStatic).GetMethod("ZeroArgs"));

            ReplacedStatic.ZeroArgs();

            _callSpyAspect.Verify(x => x.Execute(), Moq.Times.Once());
        }

        [TestMethod]
        public void WhenCallReplacedMethod0ArgsThenExecuteAfterMethod()
        {
            var spy = _callSpyAspect.Object;
            Instrumentation.AddAfterAction("ZeroArgs", (x, y) =>
            {
                spy.Execute();
                return y;
            });
            Instrumentation.EncapsulateNonjittedMethod(typeof(ReplacedStatic).GetMethod("ZeroArgs"));

            ReplacedStatic.ZeroArgs();

            _callSpyAspect.Verify(x => x.Execute(), Moq.Times.Once());
        }

        public void ReplacedFoo()
        {
            var memberId = "ulli";
            //var parameters = new object[0];
            Instrumentation.BeforeMethod(memberId, null);
            Hoshi();
            //Instrumentation.AfterMethod(memberId, null, null);
        }

        [Ignore]
        [TestMethod]
        public void WhenCallReplacedMethod1ReferenceArgsThenExecuteMethodBody()
        {
            Instrumentation.EncapsulateNonjittedMethod(typeof(ReplacedStatic).GetMethod("OneReferenceArg"));

            ReplacedStatic.OneReferenceArg(typeof(string));

            _callSpy.Verify(x => x.Execute(), Moq.Times.Once());
        }

        [Ignore]
        [TestMethod]
        public void WhenCallReplacedMethodReturnThenExecuteMethodBody()
        {
            Instrumentation.EncapsulateNonjittedMethod(typeof(ReplacedStatic).GetMethod("ReturnSomething"));

            var typeName = ReplacedStatic.ReturnSomething(typeof(string));

            Assert.AreEqual("System.String", typeName);
        }
    }

    public interface ICall
    {
        void Execute();
    }

    public static class ReplacedStatic
    {
        public static ICall CallSpy { get; set; }

        public static void ZeroArgs()
        {
            CallSpy.Execute();
        }

        public static void OneReferenceArg(Type type)
        {
            CallSpy.Execute();
        }

        public static string ReturnSomething(Type type)
        {
            CallSpy.Execute();
            return type.FullName;
        }
    }
}
